package com.tsmti.tags.grid;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeFilter;
import com.google.common.collect.Lists;
import com.tsmti.core.common.constant.Constants;
import com.tsmti.core.common.constant.RedisConstants;
import com.tsmti.core.common.query.data.PropertyPreFilterable;
import com.tsmti.core.common.query.data.QueryPropertyPreFilter;
import com.tsmti.core.util.*;
import com.tsmti.system.dto.PageColDto;
import com.tsmti.system.entity.DataDictionary;
import com.tsmti.system.service.SystemPageColumnService;
import com.tsmti.tags.form.support.FreemarkerFormTagHelper;
import com.tsmti.tags.html.manager.HtmlComponentManager;
import com.tsmti.util.DictionaryUtils;
import com.tsmti.util.RedisGridFormatUtils;
import com.tsmti.util.UserUtils;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;


/**
 * @Package：com.tsmti.tags.grid
 * @Class：DataGridTag
 * @Description：
 * @Author：
 * @Date：Created in 2018/3/14 17:15
 * @Company:
 * @Version：
 * @Modified By:
 */
@SuppressWarnings("serial")
public class DataGridTag extends AbstractGridHtmlTag {

    protected HtmlComponentManager htmlComponentManager = SpringContextUtils.getApplicationContext().getBean(HtmlComponentManager.class);
    protected SystemPageColumnService systemPageColumnService = SpringContextUtils.getApplicationContext().getBean(SystemPageColumnService.class);
    private List<Map<String, Object>> columnList = new ArrayList<Map<String, Object>>();

    private List<Map<String, Object>> toobarList = new ArrayList<Map<String, Object>>();
    /**
     * 行内按钮
     */
    private List<Map<String, Object>> buttonList = new ArrayList<Map<String, Object>>();
    private List<Map<String, Object>> queryList = new ArrayList<Map<String, Object>>();
    private Map<String, List<DataDictionary>> columnDictMap = new HashMap<String, List<DataDictionary>>();
    private Map<String, String> columnRedisMap = new HashMap<>();
    /**
     * 表格唯一标示
     */
    private String id = "datagridid";
    /**
     * grid的类型,默认jqgrid
     */
    private String gridtype = "jqgrid";
    /**
     * list,form,js
     */
    private String gridShowType = "list";
    /**
     * 表格的标题
     */
    private String caption = "";
    /**
     * 从datas中加入的数据,请求的地址
     */
    private String url = "";
    /**
     * 请求的基础网页
     */
    private String baseUrl = "";
    /**
     * 行内编辑URL
     */
    private String editurl = "clientArray";
    /**
     * 是否行内编辑
     */
    private Boolean editable = Boolean.FALSE;
    /**
     * 默认为JSON,local,jsonp远程
     */
    private String datatype = "json";
    /**
     * 默认为JSON,local
     */
    private String ajaxType = "get";
    /**
     * local时的数据
     */
    private Object datas;
    /**
     * 是否分页
     */
    private Boolean pageable = Boolean.TRUE;
    /**
     * 表格宽度
     */
    private String width = "auto";
    /**
     * 表格高度
     */
    private String height = "";
    /**
     * 是否多选
     */
    private Boolean multiselect = true;

    /**
     * 宽度自适应
     */
    private Boolean shrinkToFit = false;

    /**
     * 只有点击checkbox复选框才生效
     */
    private Boolean multiboxonly = true;

    /**
     * 是否多列排序
     */
    private Boolean multiSort = Boolean.TRUE;
    private Boolean sortable = Boolean.TRUE;
    private String sortname = "";
    private String sortorder = "asc";
    private Boolean showQueryLabel = Boolean.TRUE;

    /**
     * 页码开始
     */
    private int page = 1;
    /**
     * 这个参数是要被传递到后台，树结构时候，rowNum无效
     */
    private int rowNum = 30;
    /**
     * 是否数机构
     */
    private Boolean treeGrid = Boolean.FALSE;
    /**
     * 指定那列来展开treegrid，默认为第一列，只有在treeGrid为true时起作用
     */
    private String expandColumn = "";
    /*** 树情况是否异步*/
    private Boolean async = Boolean.FALSE;
    /*** 扩展设置*/
    private String gridSetting = "";
    /*** 配置方法,为js方法，返回配置*/
    private String gridSettingCallback = "";
    /*** 页面ID*/
    private String pageId;
    /*** 双击事件*/
    private String ondblClickRow;
    /*** 初始加载事件*/
    private String loadComplete;
    /*** 表格加载*/
    private String gridComplete;
    /*** 分组表头*/
    private String groupHeaders;
    /*** 用户定义高度*/
    private int customHeight = 0;

    /*** 查询条件列数*/
    private int queryGroup = 4;

    /*** jqgrid选择行事件*/
    private String onSelectRow;
    /*** jqgrid选择行前事件*/
    private String beforeSelectRow;
    /*** jqgrid选择行编辑前事件*/
    private String beforeEditCell;
    /*** jqgrid点击单元格事件*/
    private String onCellSelect;
    /*** 是否显示行号*/
    private Boolean rownumbers = Boolean.FALSE;
    /*** 是否显示表尾*/
    private Boolean footerRow = Boolean.FALSE;

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void setId(String id) {
        this.id = id;
    }

    public String getGridtype() {
        return gridtype;
    }

    public void setGridtype(String gridtype) {
        this.gridtype = gridtype;
    }

    public String getCaption() {
        return caption;
    }

    public void setCaption(String caption) {
        this.caption = caption;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDatatype() {
        return datatype;
    }

    public void setDatatype(String datatype) {
        this.datatype = datatype;
    }

    public String getAjaxType() {
        return ajaxType;
    }

    public void setAjaxType(String ajaxType) {
        this.ajaxType = ajaxType;
    }

    public Object getDatas() {
        return datas;
    }

    public void setDatas(Object datas) {
        this.datas = datas;
    }

    public Boolean getPageable() {
        return pageable;
    }

    public void setPageable(Boolean pageable) {
        this.pageable = pageable;
    }

    public String getWidth() {
        return width;
    }

    public void setWidth(String width) {
        this.width = width;
    }

    public String getHeight() {
        return height;
    }

    public void setHeight(String height) {
        this.height = height;
    }

    public Boolean getMultiselect() {
        return multiselect;
    }

    public void setMultiselect(Boolean multiselect) {
        this.multiselect = multiselect;
    }

    public Boolean getMultiboxonly() {
        return multiboxonly;
    }

    public void setMultiboxonly(Boolean multiboxonly) {
        this.multiboxonly = multiboxonly;
    }

    public Boolean getMultiSort() {
        return multiSort;
    }

    public void setMultiSort(Boolean multiSort) {
        this.multiSort = multiSort;
    }

    public Boolean getSortable() {
        return sortable;
    }

    public void setSortable(Boolean sortable) {
        this.sortable = sortable;
    }

    public String getSortname() {
        return sortname;
    }

    public void setSortname(String sortname) {
        this.sortname = sortname;
    }

    public String getSortorder() {
        return sortorder;
    }

    public void setSortorder(String sortorder) {
        this.sortorder = sortorder;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getRowNum() {
        return rowNum;
    }

    public void setRowNum(int rowNum) {
        this.rowNum = rowNum;
    }

    public Boolean getTreeGrid() {
        return treeGrid;
    }

    public void setTreeGrid(Boolean treeGrid) {
        this.treeGrid = treeGrid;
    }

    public String getExpandColumn() {
        return expandColumn;
    }

    public void setExpandColumn(String expandColumn) {
        this.expandColumn = expandColumn;
    }

    public Boolean getAsync() {
        return async;
    }

    public void setAsync(Boolean async) {
        this.async = async;
    }

    public String getGridSetting() {
        return gridSetting;
    }

    public void setGridSetting(String gridSetting) {
        this.gridSetting = gridSetting;
    }

    public String getGridSettingCallback() {
        return gridSettingCallback;
    }

    public void setGridSettingCallback(String gridSettingCallback) {
        this.gridSettingCallback = gridSettingCallback;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public String getEditurl() {
        return editurl;
    }

    public void setEditurl(String editurl) {
        this.editurl = editurl;
    }

    public void putColumnDict(String dict) {
        columnDictMap.put(dict, DictionaryUtils.getDictList(dict));
    }
    public void putColumnRedis(String redis,String value)throws Exception {
        columnRedisMap.put(redis, RedisGridFormatUtils.getSelectOptions(redis,value));
    }

    public void addColumn(Map<String, Object> column) {
        columnList.add(column);
    }

    public Boolean getEditable() {
        return editable;
    }

    public void setEditable(Boolean editable) {
        this.editable = editable;
    }

    public String getGridShowType() {
        return gridShowType;
    }

    public void setGridShowType(String gridShowType) {
        this.gridShowType = gridShowType;
    }

    public String getPageId() {
        return pageId;
    }

    public void setPageId(String pageId) {
        this.pageId = pageId;
    }

    public void addQuery(Map<String, Object> column) {
        queryList.add(column);
    }

    public void addToolbar(Map<String, Object> toolbar) {
        toobarList.add(toolbar);
    }

    public void addButton(Map<String, Object> button) {
        buttonList.add(button);
    }

    public Boolean getShrinkToFit() {
        return shrinkToFit;
    }

    public void setShrinkToFit(Boolean shrinkToFit) {
        this.shrinkToFit = shrinkToFit;
    }

    @Override
    public int doStartTag() throws JspException {
        // 清空资源
        queryList.clear();
        columnList.clear();
        toobarList.clear();
        buttonList.clear();
        columnDictMap.clear();
        if (staticAttributes != null) {
            staticAttributes.clear();
        }
        if (StringUtils.isEmpty(baseUrl) && !StringUtils.isEmpty(url)) {
            this.baseUrl = url.substring(0, url.lastIndexOf("/"));
        }
        if (StringUtils.isEmpty(url) && !StringUtils.isEmpty(baseUrl)) {
            this.url = this.baseUrl + "/ajaxList";
        }
        // 获取实体类的所有属性，返回Field数组
        Field[] field = getClass().getDeclaredFields();
        // 遍历所有属性
        for (int j = 0; j < field.length; j++) {
            Field field2 = field[j];
            if (ObjectUtils.isBaseDataType(field2.getType())) {
                // 获取属性的名字
                String name = field[j].getName();
                setStaticAttribute(name, ReflectionUtils.invokeGetter(this, name));
            }
        }
        return EVAL_PAGE;
    }

    public Boolean getShowQueryLabel() {
        return showQueryLabel;
    }

    public void setShowQueryLabel(Boolean showQueryLabel) {
        this.showQueryLabel = showQueryLabel;
    }

    @Override
    public int doEndTag() throws JspTagException {
        try {
            writeFragment();
        } catch (JspException e) {
            e.printStackTrace();
        }
        return EVAL_PAGE;
    }

    @SuppressWarnings("rawtypes")
    private void writeFragment() throws JspException {
        if (!StringUtils.isEmpty(url)) {
            if (this.url.contains(Constants.UNKNOWN_MARK)) {
                this.url = this.url + "&gridtype=" + gridtype;
            } else {
                this.url = this.url + "?gridtype=" + gridtype;
            }
        }
        if (async) {
            this.url = this.url + "&async=1";
        }
        Map<String, Object> rootMap = new HashMap<String, Object>(16);
        String ctx = pageContext.getServletContext().getContextPath();
        String appPath = pageContext.getServletContext().getContextPath();
        String staticPath = pageContext.getServletContext().getContextPath() + "/statics";
        if (dynamicAttributes == null) {
            dynamicAttributes = new HashMap<String, Object>(16);
        }
        rootMap.put("dynamicAttributes", dynamicAttributes);
        rootMap.put("appPath", appPath);
        rootMap.put("staticPath", staticPath);
        if (datas != null) {
            String initDatas = "";
            List dataList = (List) datas;
            if (dataList != null && dataList.size() > 0) {
                Class<?> clazz = dataList.get(0).getClass();
                PropertyPreFilterable propertyPreFilterable = new QueryPropertyPreFilter();
                for (Map<String, Object> columnItem : columnList) {
                    String name = (String) columnItem.get("name");
                    propertyPreFilterable.addQueryProperty(name);
                }
                propertyPreFilterable.addQueryProperty("id");
                SerializeFilter filter = propertyPreFilterable.constructFilter(clazz);
                initDatas = JSON.toJSONString(datas, filter);
            }
            if (StringUtils.isEmpty(initDatas)) {
                initDatas = "[]";
            }
            rootMap.put("initDatas", initDatas);
            this.datatype = "local";
            // 本地访问不能进行排序
            this.sortable = Boolean.FALSE;
        }

        //处理用户自定义配置
        String pageId = this.getPageId();
        String userName = UserUtils.getUserName();
        if (!StringUtils.isEmpty(pageId)) {
            List<PageColDto> pageColDtoList = systemPageColumnService.getUserDefaultColList(pageId, userName, false);
            if (pageColDtoList != null && pageColDtoList.size() > 0) {
                Map<String, PageColDto> pageColDtoMap = new HashMap<String, PageColDto>(16);
                for (PageColDto pageCol : pageColDtoList) {
                    pageColDtoMap.put(pageCol.getColName(), pageCol);
                }
                Iterator it = columnList.iterator();
                while (it.hasNext()) {
                    Map<String, Object> obj = (Map<String, Object>) it.next();
                    String name = ConvertUtil.null2String(obj.get("name"));
                    if("opt".equals(name)) {
                        obj.put("orders", -1);
                        continue;
                    }
                    PageColDto pageColDto = pageColDtoMap.get(name);
                    if (pageColDto != null) {
                        String colText = ConvertUtil.null2String(pageColDto.getColText());
                        if (!StringUtils.isEmpty(colText)) {
                            obj.put("label", colText);
                        }
                        if(!"".equals(ConvertUtil.null2String(pageColDto.getColWidth()))) {
                            obj.put("width", ConvertUtil.null2String(pageColDto.getColWidth()));
                        }
                        obj.put("orders", pageColDto.getOrders());
                    } else {
                        obj.put("orders", -1);
                        obj.put("hidden", true);
                    }
                }
                //排序
                Collections.sort(columnList, new Comparator<Map<String, Object>>() {
                    @Override
                    public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                        Integer orders1 = Integer.valueOf(o1.get("orders").toString());
                        Integer orders2 = Integer.valueOf(o2.get("orders").toString());
                        return orders1.compareTo(orders2);
                    }
                });
            }
        }

        //queryList分组
        List<List<Map<String,Object>>> queryGroupList = Lists.partition(queryList, queryGroup);
        rootMap.put("columnList", columnList);
        rootMap.put("columnDictMap", columnDictMap);
        rootMap.put("columnRedisMap", columnRedisMap);
        rootMap.put("queryGroupList", queryGroupList);
        rootMap.put("toobarList", toobarList);
        rootMap.put("buttonList", buttonList);
        Map<String, Object> staticMap = FreemarkerFormTagHelper.getTagStatic(this, pageContext);
        rootMap.putAll(staticMap);
        String fragment = htmlComponentManager.getFragmentComponent(gridtype + "-grid", rootMap);
        if (!StringUtils.isEmpty(fragment) && !Constants.NULL.equals(fragment)) {
            // 获得编辑器
            try {
                super.pageContext.getOut().write(fragment);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public String getOndblClickRow() {
        return ondblClickRow;
    }

    public void setOndblClickRow(String ondblClickRow) {
        this.ondblClickRow = ondblClickRow;
    }

    public String getLoadComplete() {
        return loadComplete;
    }

    public void setLoadComplete(String loadComplete) {
        this.loadComplete = loadComplete;
    }

    public String getGridComplete() {
        return gridComplete;
    }

    public void setGridComplete(String gridComplete) {
        this.gridComplete = gridComplete;
    }

    public String getGroupHeaders() {
        return groupHeaders;
    }

    public void setGroupHeaders(String groupHeaders) {
        this.groupHeaders = groupHeaders;
    }
    
    public int getCustomHeight() {
        return customHeight;
    }

    public void setCustomHeight(int customHeight) {
        this.customHeight = customHeight;
    }

    public int getQueryGroup() {
        return queryGroup;
    }

    public void setQueryGroup(int queryGroup) {
        this.queryGroup = queryGroup;
    }
    public String getOnSelectRow() {
        return onSelectRow;
    }

    public void setOnSelectRow(String onSelectRow) {
        this.onSelectRow = onSelectRow;
    }

    public String getBeforeSelectRow() {
        return beforeSelectRow;
    }

    public void setBeforeSelectRow(String beforeSelectRow) {
        this.beforeSelectRow = beforeSelectRow;
    }

    public String getBeforeEditCell() {
        return beforeEditCell;
    }

    public void setBeforeEditCell(String beforeEditCell) {
        this.beforeEditCell = beforeEditCell;
    }

    public String getOnCellSelect() {
        return onCellSelect;
    }

    public void setOnCellSelect(String onCellSelect) {
        this.onCellSelect = onCellSelect;
    }

    public Boolean getRownumbers() {
        return rownumbers;
    }

    public void setRownumbers(Boolean rownumbers) {
        this.rownumbers = rownumbers;
    }

    public Boolean getFooterRow() {
        return footerRow;
    }

    public void setFooterRow(Boolean footerRow) {
        this.footerRow = footerRow;
    }
}